import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { prefixStyle, CancelBubble } from 'common/js/dom'
import {
  ScrollWrapper
} from './style'

const userSelect = prefixStyle('user-select')

class Scroll extends PureComponent {
  constructor (props) {
    super(props)

    this.state = {
      showScroll: false
    }

    this.scrollWheel = this.scrollWheel.bind(this)
    this.scrollDown = this.scrollDown.bind(this)
    this.scrollEnter = this.scrollEnter.bind(this)
    this.scrollLeave = this.scrollLeave.bind(this)
  }

  componentWillReceiveProps (nextProps) {
    this.onResize()
  }

  componentDidMount () {
    if (!this.props.customInitScroll) {
      this.initScroll()
    }

    this.onmouseWheel(this.scroll, this.scrollWheel)
  }

  render () {
    const { direction } = this.props
    const { showScroll } = this.state

    return (
      <ScrollWrapper
        innerRef={scroll => this.scroll = scroll}
        className={direction === 'y' ? 'Yscroll' : 'Xscroll'}
      >
        <div
          ref={wrapper => this.scrollWrapper = wrapper}
          className="scroll-wrapper"
        >
          {this.props.children}
        </div>
        <div
          ref={box => this.scrollBox = box}
          className={showScroll ? 'scroll-box' : 'scroll-box hide'}
        >
          <div
            ref={move => this.scrollMove = move}
            className="scroll-move"
            onMouseDown={this.scrollDown}
            onMouseEnter={this.scrollEnter}
            onMouseLeave={this.scrollLeave}
          ></div>
        </div>
      </ScrollWrapper>
    )
  }

  onResize () {
    if (!this.state.showScroll) {
      this.initScroll()
      return
    }

    if (
      this.scroll === undefined ||
      this.scrollWrapper === undefined ||
      this.scrollBox === undefined ||
      this.scrollMove === undefined
    ) {
      return
    }

    this.refreshScroll()
  }

  refreshScroll () {
    if (this.props.direction === 'x') {
      this.sW = this.scroll.offsetWidth
      this.swW = this.scrollWrapper.offsetWidth
      this.sbW = this.scrollBox.offsetWidth
      this.swL = this.scrollWrapper.offsetLeft
      this.smL = this.scrollMove.offsetLeft

      if (this.sW - this.swW >= 0) {
        this.scrollWrapper.style.left = ''
        this.scrollMove.style.left = ''
        this.setState(() => ({
          showScroll: false
        }))
        return
      }

      if (this.swL < this.sW - this.swW) {
        this.scrollWrapper.style.left = `${this.sW - this.swW}px`
      }
      this.scrollMove.style.width = `${Math.round(this.sW / this.swW * this.sW)}px`
      this.scrollMove.style.left = `${-(this.swL / this.swW * this.sW)}px`
    } else {
      this.sH = this.scroll.offsetHeight
      this.swH = this.scrollWrapper.offsetHeight
      this.sbH = this.scrollBox.offsetHeight
      this.swT = this.scrollWrapper.offsetTop
      this.smT = this.scrollMove.offsetTop

      if (this.sH - this.swH >= 0) {
        this.scrollWrapper.style.top = ''
        this.scrollMove.style.top = ''
        this.setState(() => ({
          showScroll: false
        }))
        return
      }

      if (this.swT < this.sH - this.swH) {
        this.scrollWrapper.style.top = `${this.sH - this.swH}px`
      }
      this.scrollMove.style.height = `${Math.round(this.sH / this.swH * this.sH)}px`
      this.scrollMove.style.top = `${-(this.swT / this.swH * this.sH)}px`
    }
  }

  scrollToStart () {
    if (this.props.direction === 'x') {
      this.scrollMove.style.left = ''
      this.scrollWrapper.style.left = ''
    } else {
      this.scrollMove.style.top = ''
      this.scrollWrapper.style.top = ''
    }
  }

  scrollToEnd () {
    if (this.props.direction === 'x') {
      let X = this.scroll.offsetWidth - this.scrollMove.offsetWidth

      this.scrollMove.style.left = `${X}px`
      this.scrollWrapper.style.left = `${-X / (this.sW / this.swW)}px`
    } else {
      let Y = this.scroll.offsetHeight - this.scrollMove.offsetHeight

      this.scrollMove.style.top = `${Y}px`
      this.scrollWrapper.style.top = `${-Y / (this.sH / this.swH)}px`
    }
  }

  scrollDown (event) {
    if (!this.state.showScroll) {
      return
    }
    if (this.props.direction === 'x') {
      let startX = event.clientX - this.scrollMove.offsetLeft
      document.onmousemove = (event) => {
        document.getElementsByTagName('html')[0].style[userSelect] = 'none'
        document.getElementsByTagName('html')[0].style['cursor'] = 'default'

        this.scrollEnter()

        let X = event.clientX - startX

        if (X < 0) {
          X = 0
        }

        if (X > this.scroll.offsetWidth - this.scrollMove.offsetWidth) {
          X = this.scroll.offsetWidth - this.scrollMove.offsetWidth
        }

        this.scrollMove.style.left = `${X}px`
        this.scrollWrapper.style.left = `${-X / (this.sW / this.swW)}px`
      }
      document.onmouseup = () => {
        this.scrollLeave()
        document.getElementsByTagName('html')[0].style[userSelect] = ''
        document.getElementsByTagName('html')[0].style['cursor'] = ''
        document.onmousemove = null
      }
    } else {
      let startY = event.clientY - this.scrollMove.offsetTop
      document.onmousemove = (event) => {
        document.getElementsByTagName('html')[0].style[userSelect] = 'none'
        document.getElementsByTagName('html')[0].style['cursor'] = 'default'

        this.scrollEnter()

        let Y = event.clientY - startY

        if (Y < 0) {
          Y = 0
        }

        if (Y > this.scroll.offsetHeight - this.scrollMove.offsetHeight) {
          Y = this.scroll.offsetHeight - this.scrollMove.offsetHeight
        }

        this.scrollMove.style.top = `${Y}px`
        this.scrollWrapper.style.top = `${-Y / (this.sH / this.swH)}px`
      }
      document.onmouseup = () => {
        this.scrollLeave()
        document.getElementsByTagName('html')[0].style[userSelect] = ''
        document.getElementsByTagName('html')[0].style['cursor'] = ''
        document.onmousemove = null
      }
    }
  }

  scrollWheel (event, down) {
    if (!this.state.showScroll) {
      return
    }

    let wheel = (event.wheelDelta / 120) || -(event.detail / 3)

    if (this.props.direction === 'x') {
      // let smL = this.scrollMove.offsetLeft
      let swL = this.scrollWrapper.offsetLeft

      let swX = swL + (wheel * 40)
      let smX = -swX / this.swW * this.sW

      if (smX < 0) {
        smX = 0
      }

      if (smX > this.scroll.offsetWidth - this.scrollMove.offsetWidth) {
        smX = this.scroll.offsetWidth - this.scrollMove.offsetWidth
      }

      if (swX < this.sW - this.swW) {
        swX = this.sW - this.swW
      }

      if (swX > 0) {
        swX = 0
      }

      this.scrollMove.style.left = `${smX}px`
      this.scrollWrapper.style.left = `${swX}px`
    } else {
      // let smT = this.scrollMove.offsetTop
      let swT = this.scrollWrapper.offsetTop

      let swY = swT + (wheel * 40)
      let smY = -swY / this.swH * this.sH

      if (smY < 0) {
        smY = 0
      }

      if (smY > this.scroll.offsetHeight - this.scrollMove.offsetHeight) {
        smY = this.scroll.offsetHeight - this.scrollMove.offsetHeight
      }

      if (swY < this.sH - this.swH) {
        swY = this.sH - this.swH
      }

      if (swY > 0) {
        swY = 0
      }

      this.scrollMove.style.top = `${smY}px`
      this.scrollWrapper.style.top = `${swY}px`
    }

    CancelBubble(event)
  }

  scrollEnter () {
    if (!this.props.hoverColor) {
      return
    }
    this.scrollMove.style.backgroundColor = this.props.hoverColor
  }

  scrollLeave () {
    if (!this.props.hoverColor) {
      return
    }
    this.scrollMove.style.backgroundColor = this.props.color
  }

  onmouseWheel (obj, cbfn) { // 鼠标滚轮兼容事件
    var down = true
    if (window.navigator.userAgent.indexOf('Firefox') > -1) {
      obj.addEventListener('DOMMouseScroll', fn, false)
    } else {
      obj.onmousewheel = fn
    }

    function fn (event) {
      var e = event || window.event
      if (e.detail) {
        down = e.detail > 0
      } else {
        down = e.wheelDelta < 0
      }
      cbfn.call(obj, e, down)
      if (e.preventDefault) {
        e.preventDefault()
      } else {
        window.event.returnValue = false
      }
      return false
    }
  }

  initScroll () {
    // this.scroll = this.$refs['scroll']
    // this.scrollWrapper = this.$refs['scroll-warpper']

    // this.scrollBox = this.$refs['scroll-box']
    // this.scrollMove = this.$refs['scroll-move']

    if (
      this.scroll === undefined ||
      this.scrollWrapper === undefined ||
      this.scrollBox === undefined ||
      this.scrollMove === undefined
    ) {
      return
    }

    if (this.props.direction === 'x') {
      this.scrollMove.style.left = ''
      this.scrollWrapper.style.left = ''

      this.sW = this.scroll.offsetWidth
      this.swW = this.scrollWrapper.offsetWidth

      if (this.sW < this.swW) {
        this.setState(() => ({
          showScroll: true
        }))
        setTimeout(() => {
          if (this.props.isNeedPad) {
            this.scrollWrapper.style.paddingBottom = `${+this.props.width + 2}px`
          }

          this.scrollBox.style.height = `${this.props.width}px`
          this.scrollBox.style.backgroundColor = this.props.bgColor

          this.scrollMove.style.width = `${Math.round(this.sW / this.swW * this.sW)}px`
          this.scrollMove.style.backgroundColor = this.props.color
        }, 20)
      } else {
        this.scrollWrapper.style.paddingBottom = ''
        this.setState(() => ({
          showScroll: false
        }))
      }
    } else {
      this.scrollMove.style.top = ''
      this.scrollWrapper.style.top = ''

      this.sH = this.scroll.offsetHeight
      this.swH = this.scrollWrapper.offsetHeight
      if (this.sH < this.swH) {
        this.setState(() => ({
          showScroll: true
        }))
        setTimeout(() => {
          if (this.props.isNeedPad) {
            this.scrollWrapper.style.paddingRight = `${+this.props.width + 2}px`
          }

          this.scrollBox.style.width = `${this.props.width}px`
          this.scrollBox.style.backgroundColor = this.props.bgColor

          this.scrollMove.style.height = `${Math.round(this.sH / this.swH * this.sH)}px`
          this.scrollMove.style.backgroundColor = this.props.color
        }, 20)
      } else {
        this.scrollWrapper.style.paddingRight = ''
        this.setState(() => ({
          showScroll: false
        }))
      }
    }
  }
}

Scroll.propsTypes = {
  data: PropTypes.array,
  width: PropTypes.string,
  BgColor: PropTypes.string,
  color: PropTypes.string,
  hoverColor: PropTypes.string,
  isNeedPad: PropTypes.bool,
  customInitScroll: PropTypes.bool,
  direction: PropTypes.string
}

Scroll.defaultProps = {
  data: [],
  width: '15',
  BgColor: 'white',
  color: 'red',
  hoverColor: '',
  isNeedPad: true,
  customInitScroll: false,
  direction: 'y'
}

const mapState = (state) => ({
  bodySize: state.getIn(['app', 'bodySize'])
})

export default connect(mapState, null)(Scroll)
